﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Surface.Presentation.Controls;

using SurfaceCardsBoardLibrary.Interfaces;

namespace SurfaceCardsBoardLibrary
{
    /// <summary>
    /// Surface card game helper class.
    /// </summary>
    public static class SurfaceCardGameHelper
    {
        /// <summary>
        /// Checks whether <paramref name="item"/>'s content implements ICard or not.
        /// </summary>
        /// <param name="item">The ScatterViewItem to check.</param>
        /// <returns>Returns true if the <paramref name="item"/>'s content implement ICard.</returns>
        public static bool IsCard(this ScatterViewItem item)
        {
            if (item == null)
                throw new NullReferenceException();
            return item.DataContext is ICard;
        }

        public static bool IsFreeCard(this ScatterViewItem item)
        {
            if (item == null)
                throw new NullReferenceException();

            if (item.IsCard())
                return (item.ToCard().Parent is IDeck) == false;
            return false;
        }

        public static bool IsDeckCard(this ScatterViewItem item)
        {
            if (item == null)
                throw new NullReferenceException();

            if (item.IsCard())
                return item.ToCard().Parent is IDeck;
            return false;
        }

        public static bool IsDeck(this ScatterViewItem item)
        {
            if (item == null)
                throw new NullReferenceException();

            return item.DataContext is IDeck;
        }

        public static bool IsManipulableObject(this ScatterViewItem item)
        {
            if (item == null)
                throw new NullReferenceException();

            return item.DataContext is IManipulableObject;
        }

        /// <summary>
        /// Retrieves the instance of ICard contained within <paramref name="item"/>.
        /// </summary>
        /// <param name="item">The ScatterViewItem from which to extract the card.</param>
        /// <returns>
        /// Returns the instance of the card contained within <paramref name="item"/>, returns null if the content does not implements ICard.
        /// </returns>
        public static ICard ToCard(this ScatterViewItem item)
        {
            if (item == null)
                throw new NullReferenceException();
            return item.DataContext as ICard;
        }

        public static IDeck ToDeck(this ScatterViewItem item)
        {
            if (item == null)
                throw new NullReferenceException();
            return item.DataContext as IDeck;
        }

        public static IManipulableObject ToManipulableObject(this ScatterViewItem item)
        {
            if (item == null)
                throw new NullReferenceException();
            return item.DataContext as IManipulableObject;
        }

        /// <summary>
        /// Retrieves a list of the ICard instances contained within a list of ScatterViewItems.
        /// </summary>
        /// <param name="list">The ScatterViewItems list from which to extract the cards list.</param>
        /// <returns>Returns a collection of card instances.</returns>
        /// <remarks>
        /// This function ignores the ScatterViewItems whose content does not implement ICard.
        /// Therefore the list returned may not have the same number of elements as the parameter list.
        /// </remarks>
        public static IEnumerable<ICard> ToCards(this IEnumerable<ScatterViewItem> list)
        {
            if (list == null)
                throw new NullReferenceException();

            return list.Select(svi => svi.ToCard());
        }

        public static IEnumerable<IDeck> ToDecks(this IEnumerable<ScatterViewItem> list)
        {
            if (list == null)
                throw new NullReferenceException();

            return list.Select(svi => svi.ToDeck());
        }

        public static IEnumerable<IManipulableObject> ToManipulableObjects(this IEnumerable<ScatterViewItem> list)
        {
            if (list == null)
                throw new NullReferenceException();

            return list.Select(svi => svi.ToManipulableObject());
        }

        public static IEnumerable<ScatterViewItem> FilterOnDecks(this IEnumerable<ScatterViewItem> list)
        {
            if (list == null)
                throw new NullReferenceException();

            return list.Where(svi => svi.IsDeck());
        }

        public static IEnumerable<ScatterViewItem> FilterOnCards(this IEnumerable<ScatterViewItem> list)
        {
            if (list == null)
                throw new NullReferenceException();

            return list.Where(svi => svi.IsCard());
        }

        public static IEnumerable<ScatterViewItem> FilterOnManipulableObjects(this IEnumerable<ScatterViewItem> list)
        {
            if (list == null)
                throw new NullReferenceException();

            return list.Where(svi => svi.IsManipulableObject());
        }

        public static IEnumerable<ScatterViewItem> FilterOnFreeCards(this IEnumerable<ScatterViewItem> list)
        {
            if (list == null)
                throw new NullReferenceException();

            return list.FilterOnCards().Where(svi => svi.IsFreeCard());
        }

        public static IEnumerable<ScatterViewItem> FilterOnDeckCards(this IEnumerable<ScatterViewItem> list)
        {
            if (list == null)
                throw new NullReferenceException();
            return list.FilterOnCards().Where(svi => svi.IsDeckCard());
        }

        /// <summary>
        /// Gets the list of ScatterViewItems containing instances of ICards within a list of ScatterViewItems.
        /// </summary>
        /// <param name="source">Source list of ScatterViewItems to filter.</param>
        /// <param name="cards">List of cards to find.</param>
        /// <returns>Returns the list of ScatterViewItems containing one of the cards in <paramref name="cards"/>.</returns>
        public static IEnumerable<ScatterViewItem> GetScatterViewItemsContainingCards(this IEnumerable<ScatterViewItem> source, IEnumerable<ICard> cards)
        {
            if (source == null)
                throw new NullReferenceException("source");
            if (cards == null)
                throw new NullReferenceException("cards");

            var filtered_source = from item in source
                                  where item.DataContext is ICard
                                  select item;

            var query = from svi in filtered_source
                        join card in cards on svi.DataContext equals card
                        select svi;

            return query;
        }

        public static ScatterViewItem GetScatterViewItemForItem(this ScatterView scatterview, IManipulableObject item)
        {
            return scatterview.ItemContainerGenerator.ContainerFromItem(item) as ScatterViewItem;
        }
    }
}
